package com.modular.extra.ai.action;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.task.Task;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import com.c.Constant;
import com.modular.extra.ai.FactoryAiOpt;
import com.modular.extra.ai.vision.record.bean.AiRecord;
import ntd.action.ActionAbs;
import ntd.action.bo.ActionInBo;
import ntd.action.bo.ActionInfo;
import ntd.action.bo.ActionOutBo;
import ntd.remote.file.ComRemoteFile;
import ntd.remote.file.bo.ComRemoteFileBO;
import ntd.remote.link.ComRegistryClient;
import ntd.tool.ToolCron;
import ntd.tool.ToolId;
import ntd.util.UtilCatch;
import ntd.util.UtilRun;
import ntd.util.config.common.exception.ComException;
import ntd.util.frame.javacv.ComVisionApi;
import ntd.util.frame.javacv.action.bean.VisionModelDo;
import ntd.util.frame.javacv.action.bo.ImgAnalysisInBo;
import ntd.util.frame.javacv.bo.CameraBO;
import ntd.util.frame.javacv.config.AiConfig;
import ntd.util.frame.javacv.remote.AiVisionRemote;
import ntd.util.frame.javacv.vlc.FactoryVlc;
import ntd.util.util.ToolDuration;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * 数据质量
 */
public class ActionImgAnalysis extends ActionAbs {

    List<ImgAnalysisInBo> imgAnalysisInBos = new ArrayList<>();

    private static int aiRemoteIndex = 0;

    @Override
    public ActionInfo info() {
        return new ActionInfo("机器视觉图片分析", "ai-vision-img-analysis-20230607", this);
    }

    public ActionImgAnalysis() {
    }

    @Override
    public ActionOutBo handle() {
        UtilRun.onlyOne("ai-vision-img-analysis-init-20230607", this::init);

        ImgAnalysisInBo imgAnalysisInBo;
        if (MapUtil.isNotEmpty(actionInBo.getData())) {
            imgAnalysisInBo = BeanUtil.toBean(actionInBo.getData(), ImgAnalysisInBo.class);
        } else {
            imgAnalysisInBo = JSONUtil.toBean(actionInBo.getDataStr(), ImgAnalysisInBo.class);
        }

        // 验证入参
        verify(imgAnalysisInBo);
        ToolDuration.duration(() -> {
            // 加入队列
            imgAnalysisInBos.add(imgAnalysisInBo);
        }, StrUtil.format("[{}]加入分析", imgAnalysisInBo.getCameraCode()));
        return new ActionOutBo("已加入分析");
    }

    public void init() {
        CronUtil.schedule("0 */2 * * * *", (Task) () -> {
            // 按模型分组
            List<AiVisionRemote> aiVisionRemotes = ComVisionApi.analysisRemoteList();

            if (aiVisionRemotes.size() < 1) {
                StaticLog.error("无可用AI服务器，请检查后重试!");
                return;
            }
            List<ImgAnalysisInBo> imgAnalysisInBosTemp = this.imgAnalysisInBos;
            this.imgAnalysisInBos = new ArrayList<>();

            List<VisionModelDo> visionModelDos = FactoryAiOpt.OPT_VISION_MODEL.cacheListAll();

            for (VisionModelDo visionModelDo : visionModelDos) {
                Collection<ImgAnalysisInBo> modeCameras = CollectionUtil.filterNew(imgAnalysisInBosTemp, imgAnalysisInBo ->
                        imgAnalysisInBo.getVisionModelCodes().contains(visionModelDo.getCode()));
                if (CollectionUtil.isNotEmpty(modeCameras)) {
                    String currentDateDay = DateUtil.format(DateUtil.date(), Constant.DATE_FORMAT_WLW_FOUR);

                    String path = StrUtil.format("{}-{}-{}", visionModelDo.getCode(), currentDateDay, ToolId.genId());
                    String remoteFtpPath = StrUtil.format("{}/{}", AiConfig.AI_SERVER_ASYNC_FILE_PATH, path);

                    AiVisionRemote aiVisionRemote = aiVisionRemotes.get(aiRemoteIndex++ % aiVisionRemotes.size());

                    CountDownLatch countDownLatchUp = ThreadUtil.newCountDownLatch(modeCameras.size());
                    for (ImgAnalysisInBo modeCamera : modeCameras) {
                        ThreadUtil.execAsync(() -> UtilCatch.tryCatchNoRes(() -> {
                            String imgName = StrUtil.format("{}-{}-{}-{}-image.jpg", modeCamera.getMn(), modeCamera.getCameraCode(), modeCamera.getDatetime(),
                                    visionModelDo.getCode());
                            // 文件传输
                            ComRemoteFileBO comRemoteFileBO = new ComRemoteFileBO();
                            comRemoteFileBO.setRemoteCode(aiVisionRemote.aiServerDo.getCode());
                            comRemoteFileBO.setPath(remoteFtpPath + "/" + imgName);
                            ComRemoteFile.me.add(comRemoteFileBO, modeCamera.getImg());

                            // 记录存储
                            AiRecord aiRecord = new AiRecord();
                            aiRecord.setPointCode(modeCamera.getMn());
                            aiRecord.setCameraIndexCode(modeCamera.getCameraCode());
                            aiRecord.setFileName(imgName);
                            aiRecord.setAiModeType(visionModelDo.getCode());
                            aiRecord.setAnalyticsTime(modeCamera.getDatetime());
                            aiRecord.setFileType("video");
                            FactoryAiOpt.OPT_AI_RECORD.syncBean(aiRecord);
                        }, countDownLatchUp::countDown));
                    }
                    UtilCatch.tryCatchNoRes(countDownLatchUp::await);

                    // 调用分析
                    aiVisionRemote.analyse(remoteFtpPath, visionModelDo.getCode(), visionModelDo.getPortNormal());
                }
            }

        });
        ToolCron.initTask();
    }

    private void verify(ImgAnalysisInBo imgAnalysisInBo) {
        String cameraCode = imgAnalysisInBo.getCameraCode();
        if (StrUtil.isBlank(cameraCode)) {
            throw new ComException("监控设备编码为空");
        }
        if (ArrayUtil.isEmpty(imgAnalysisInBo.getImg())) {
            throw new ComException("{} - 图片不能为空", cameraCode);
        }
        if (CollectionUtil.isEmpty(imgAnalysisInBo.getVisionModelCodes())) {
            throw new ComException("{} - 分析模型不能为空", cameraCode);
        }
        // 判断重复
        ImgAnalysisInBo one = CollectionUtil.findOne(imgAnalysisInBos, item ->
                imgAnalysisInBo.getCameraCode().equals(item.getCameraCode()));
        if (ObjectUtil.isNotNull(one)) {
            throw new ComException("{} - 存在重复分析", cameraCode);
        }
    }

    public static void main(String[] args) {
        ThreadUtil.execAsync(() -> {
            ComRegistryClient.run("client-code-" + RandomUtil.randomString(10), "客户端-测试", "61.52.247.249", 13021);
        });

        ActionInBo requestInfo = new ActionInBo();

        List<String> modelTypes = ListUtil.of("Person", "WaterGarbage");

        CameraBO cameraBO = ComVisionApi.initCameraList().get(1);

        byte[] snapshotAboutBytes = FactoryVlc.getSnapshotAboutBytes(cameraBO.initRtspUrl());

        ImgAnalysisInBo imgAnalysisInBo = new ImgAnalysisInBo("135135813851", cameraBO.getCode(), snapshotAboutBytes, modelTypes);

        requestInfo.setDataStr(JSONUtil.toJsonStr(imgAnalysisInBo));

        new ActionImgAnalysis().execute(requestInfo);
    }
}
